using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.ServiceModel;
using System.Threading;
using AutoMapper;
using Core;
using IglooCoder.Commons.WcfNhibernate;
using Infrastucture;
using WcfService1.DTO;

namespace WcfService1
{
    // NOTE: You can use the "Rename" command on the "Refactor" PurchaseReturn to change the class name "PurchaseReturnServices" in code, svc and config file together.
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    [NHibernateContext]
    public class PurchaseReturnServices : IPurchaseReturnServices
    {
        private readonly PurchaseReturnRepository PurchaseReturnRepository;
        private readonly InventoryWarehouseRepository _iwRepository;
        private readonly MutasiStokRepository _mutasiStokRepository;
        private readonly WcfSessionStorage _session;
        private InventoryRepository InventoryRep;
        private AppParamRepository paramRepository;


        public PurchaseReturnServices()
        {
            Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
            _session = new WcfSessionStorage();
            PurchaseReturnRepository = new PurchaseReturnRepository(_session);
            InventoryRep = new InventoryRepository(_session);
            _mutasiStokRepository = new MutasiStokRepository(_session);
            _iwRepository = new InventoryWarehouseRepository(_session);
            paramRepository = new AppParamRepository(_session);
        }

        #region IPurchaseReturnServices Members

        public List<PurchaseReturnDTO> GetList(int page, out long recordCount, string sortProperty = null,
                                               string sortType = "ASC")
        {
            var PurchaseReturns = new List<PurchaseReturn>();
            var Results = new List<PurchaseReturnDTO>();

            if (string.IsNullOrEmpty(sortProperty))
            {
                PurchaseReturns = PurchaseReturnRepository.GetDataPaged(page, 30, "PRDate", "DESC").ToList();
            }
            else
            {
                PurchaseReturns = PurchaseReturnRepository.GetDataPaged(page, 30, sortProperty, sortType).ToList();
            }

            recordCount = PurchaseReturnRepository.RecordCount;

            PurchaseReturns.ForEach(x =>
                                        {
                                            var PurchaseReturnDto = new PurchaseReturnDTO();
                                            Mapper.Map(x, PurchaseReturnDto);
                                            //AutoMapper.Mapper.Map(x.ParentPurchaseReturn, PurchaseReturnDto.ParentPurchaseReturn);
                                            Results.Add(PurchaseReturnDto);
                                        }
                );

            return Results;
        }

        public bool Save(PurchaseReturnDTO PurchaseReturnDTO)
        {
           
            bool res;
            bool IsNew = false;
            try
            {
                PurchaseReturn PurchaseReturn =
                    PurchaseReturnRepository.GetDataOne(x => x.PRNo == PurchaseReturnDTO.PRNo);

                var paramRounded = paramRepository.GetDataOne(x => x.AppParamName == "BatasRound");
                Decimal batasRounded = Decimal.Parse(paramRounded.AppParamValue);

                if (PurchaseReturn == null)
                {
                    PurchaseReturn = new PurchaseReturn();
                    IsNew = true;
                }
                
                PurchaseReturnRepository
                    .ExecuteTransactionNative(() =>
                                                  {
                                                      if (!IsNew)
                                                      {

                                                          //Jika Status Void dan Close tdk boleh Update
                                                          if (PurchaseReturn.Status == (int)Status.Void)
                                                              throw new Exception("Tidak bisa di Update Status sudah Close atau Void!");

                                                          DateTime currDate =
                                                         _mutasiStokRepository.GetDataOne(
                                                             x => x.ReferenceNumber == PurchaseReturn.PRNo).
                                                             TglMutasi;
                                                          _mutasiStokRepository.DeleteMutasiStok(PurchaseReturn.PRNo);
                                                          var PR = new PurchaseReturn();
                                                          PR.modified_date = DateTime.Now;
                                                          PR.created_date = PurchaseReturn.created_date;
                                                          Mapper.Map(PurchaseReturnDTO, PR);
                                                          PurchaseReturnRepository.Session.SaveOrUpdateCopy(PR);
                                                          foreach (
                                                       PurchaseReturnDetail purchaseReturnDetail in
                                                           PR.PurchaseReturnDetails)
                                                          {
                                                              purchaseReturnDetail.Warehouse = PurchaseReturn.Warehouse;
                                                              //Mutasi Keluar
                                                              var mutasiStok = new MutasiStok();
                                                              mutasiStok.ReferenceNumber = PurchaseReturn.PRNo;
                                                              mutasiStok.SerialNumber =
                                                                  purchaseReturnDetail.Inventory.SerialNumber;
                                                              mutasiStok.TglMutasi = currDate.ToDateTimeSell();
                                                              mutasiStok.Type = PurchaseReturn.GetType().Name;
                                                              mutasiStok.QtyKeluar = purchaseReturnDetail.Qty;
                                                              MutasiStok mutasiLast =
                                                                  _mutasiStokRepository.FindLastMutasi(
                                                                      mutasiStok.SerialNumber,
                                                                      purchaseReturnDetail.Warehouse.KodeWarehouse,
                                                                      mutasiStok.TglMutasi
                                                                      );

                                                              if (purchaseReturnDetail.Inventory.Item.IsRounded)
                                                                  mutasiLast.QtySisa = Math.Round(
                                                                      mutasiLast.QtySisa, 2,MidpointRounding.AwayFromZero);

                                                              mutasiStok.QtySisa = mutasiLast.QtySisa - mutasiStok.QtyKeluar;
                                                              mutasiStok.SheetKeluar = purchaseReturnDetail.Tinggi;
                                                              mutasiStok.SheetSisa = mutasiLast.SheetSisa - mutasiStok.SheetKeluar;
                                                            
                                                              mutasiStok.KodeWarehouse =
                                                                  purchaseReturnDetail.Warehouse.KodeWarehouse;
                                                              if (mutasiStok.QtySisa < 0)
                                                                  throw new Exception(mutasiStok.SerialNumber + " Stok tidak mencukupi!");
                                                              if (purchaseReturnDetail.Inventory.Item.IsRounded)
                                                                  if (mutasiStok.QtySisa < batasRounded)
                                                                      mutasiStok.QtySisa = 0;
                                                              _mutasiStokRepository.SaveOrUpdate(mutasiStok,purchaseReturnDetail.Inventory.KodePallet);
                                                          }
                                                      }else
                                                      {
                                                          Mapper.Map(PurchaseReturnDTO, PurchaseReturn);
                                                          //Untuk New entry dari transaksi bukan dari email
                                                          if (String.IsNullOrEmpty(PurchaseReturn.PRNo))
                                                                        PurchaseReturn.PRNo = GetLastPRNo();
                                                          foreach (
                                                           PurchaseReturnDetail purchaseReturnDetail in
                                                               PurchaseReturn.PurchaseReturnDetails)
                                                          {
                                                              purchaseReturnDetail.PurchaseReturnDetailId = 0;
                                                              purchaseReturnDetail.Warehouse = PurchaseReturn.Warehouse;
                                                              //Mutasi Keluar
                                                              var mutasiStok = new MutasiStok();
                                                              mutasiStok.ReferenceNumber = PurchaseReturn.PRNo;
                                                              mutasiStok.SerialNumber =
                                                                  purchaseReturnDetail.Inventory.SerialNumber;
                                                              mutasiStok.TglMutasi = PurchaseReturn.PRDate.ToDateTimeSell();
                                                              mutasiStok.Type = PurchaseReturn.GetType().Name;
                                                              mutasiStok.QtyKeluar = purchaseReturnDetail.Qty;
                                                              MutasiStok mutasiLast =
                                                                  _mutasiStokRepository.FindLastMutasi(
                                                                      mutasiStok.SerialNumber,
                                                                      purchaseReturnDetail.Warehouse.KodeWarehouse,
                                                                      mutasiStok.TglMutasi
                                                                      );

                                                              if (purchaseReturnDetail.Inventory.Item.IsRounded)
                                                                  mutasiLast.QtySisa = Math.Round(
                                                                      mutasiLast.QtySisa, 2, MidpointRounding.AwayFromZero);

                                                              mutasiStok.QtySisa = mutasiLast.QtySisa - mutasiStok.QtyKeluar;
                                                              mutasiStok.SheetKeluar = purchaseReturnDetail.Tinggi;
                                                              mutasiStok.SheetSisa = mutasiLast.SheetSisa - mutasiStok.SheetKeluar;
                                                             
                                                              mutasiStok.KodeWarehouse =
                                                                  purchaseReturnDetail.Warehouse.KodeWarehouse;
                                                              if (mutasiStok.QtySisa < 0)
                                                                  throw new Exception(mutasiStok.SerialNumber + " Stok tidak mencukupi!");
                                                              if (purchaseReturnDetail.Inventory.Item.IsRounded)
                                                                  if (mutasiStok.QtySisa < batasRounded)
                                                                      mutasiStok.QtySisa = 0;
                                                              _mutasiStokRepository.SaveOrUpdate(mutasiStok,purchaseReturnDetail.Inventory.KodePallet);
                                                             
                                                          }
                                                          PurchaseReturnRepository.SaveOrUpdate(PurchaseReturn);
                                                      }
                                                 });

                res = true;
            }
            catch (Exception ex)
            {
                res = false;
                throw ex;
            }

            return res;
        }


        public bool Delete(PurchaseReturnDTO PurchaseReturnDto)
        {
            bool res;
            try
            {
                PurchaseReturn PurchaseReturn =
                    PurchaseReturnRepository.GetDataOne(x => x.PRNo == PurchaseReturnDto.PRNo);
                PurchaseReturnRepository.ExecuteTransactionNative(
                    () =>
                        {
                            _mutasiStokRepository.DeleteMutasiStok(PurchaseReturn.PRNo);
                            //PurchaseReturnRepository.Delete(PurchaseReturn);
                            PurchaseReturn.Status = 2;
                            PurchaseReturnRepository.SaveOrUpdate(PurchaseReturn);
                        }
                    );

                res = true;
            }
            catch (Exception)
            {
                res = false;
            }

            return res;
        }


        public List<PurchaseReturnDTO> GetListByCriteria(Dictionary<String, Object> criteria, string expression,
                                                         int page, out long recordCount)
        {
            var PurchaseReturns = new List<PurchaseReturn>();
            var Results = new List<PurchaseReturnDTO>();
            PurchaseReturns = PurchaseReturnRepository.GetDataPaged(criteria, expression, page, 30).ToList();
            recordCount = PurchaseReturnRepository.RecordCount;
            PurchaseReturns.ForEach(x =>
                                        {
                                            var PurchaseReturnDto = new PurchaseReturnDTO();
                                            Mapper.Map(x, PurchaseReturnDto);
                                            Results.Add(PurchaseReturnDto);
                                        }
                );

            return Results;
        }


        public List<PurchaseReturnDTO> GetAllPurchaseReturn()
        {
            List<PurchaseReturn> PurchaseReturns = PurchaseReturnRepository.FetchAll().ToList();
            var Results = new List<PurchaseReturnDTO>();
            PurchaseReturns.ForEach(x =>
                                        {
                                            var PurchaseReturnDto = new PurchaseReturnDTO();
                                            Mapper.Map(x, PurchaseReturnDto);
                                            Results.Add(PurchaseReturnDto);
                                        }
                );

            return Results;
        }


        public PurchaseReturnDTO GetPurchaseReturn(String PRNo)
        {
            PurchaseReturn PurchaseReturn = PurchaseReturnRepository.GetDataOne(x => x.PRNo == PRNo);
            var PurchaseReturnDto = new PurchaseReturnDTO();
            Mapper.Map(PurchaseReturn, PurchaseReturnDto);
            return PurchaseReturnDto;
        }

        public List<PurchaseReturnDTO> GetPurchaseReturnList(string PRNo)
        {
            List<PurchaseReturn> PurchaseReturns =
                PurchaseReturnRepository.GetDataList(x => x.PRNo.Contains(PRNo)).ToList();
            var Results = new List<PurchaseReturnDTO>();
            PurchaseReturns.ForEach(x =>
                                        {
                                            var PurchaseReturnDto = new PurchaseReturnDTO();
                                            Mapper.Map(x, PurchaseReturnDto);
                                            Results.Add(PurchaseReturnDto);
                                        }
                );

            return Results;
        }


        public string GetLastPRNo()
        {
            var appParamServices = new AppParamServices();
            AppParamDTO param = appParamServices.GetAppParamList("KodePR").FirstOrDefault();
            string res = PurchaseReturnRepository.GetMaxNumber(param.AppParamValue);
           
            if (string.IsNullOrEmpty(res))
                res = param.AppParamValue;

            string formatSO = "0000";
            string kodeSO;
            string lastNo = string.Empty;
            if (res.Length <= 4)
            {
                lastNo = formatSO;
                kodeSO = res;
            }
            else
            {
                lastNo = res.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries)[2];
                kodeSO = res.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries)[0];
            }

            string soNum = formatSO.Substring(0, formatSO.Length - (int.Parse(lastNo) + 1).ToString().Length) +
                           (int.Parse(lastNo) + 1);
            return kodeSO + "/" + DateTime.Now.Year + "/" + soNum;
        }


        public bool DeleteDetail(PurchaseReturnDetailDTO PurchaseReturnDetailDto)
        {
            bool res;
            try
            {
                var PRDetail =
                    PurchaseReturnRepository.Session.Get<PurchaseReturnDetail>(
                        PurchaseReturnDetailDto.PurchaseReturnDetailId);
                PurchaseReturnRepository.ExecuteTransactionNative(
                    () =>
                        {
                            PurchaseReturnRepository.DeleteDetail(PRDetail,
                                                                  PurchaseReturnDetailDto.PurchaseReturnDetailId);
                            _mutasiStokRepository.DeleteMutasiStok(PurchaseReturnDetailDto.NoPR,
                                                                   PRDetail.Inventory.SerialNumber);
                        }
                    );
                res = true;
            }
            catch (Exception)
            {
                res = false;
            }

            return res;
        }

        public bool SendEmail(PurchaseReturnDTO obj, String DestinationFolder)
        {
            var mailServices = new MailServices();
            PurchaseReturn Obj = PurchaseReturnRepository.GetDataOne(x => x.PRNo == obj.PRNo);
            obj = Mapper.Map(Obj, obj);
            return mailServices.SendEmail(obj,DestinationFolder);
        }

        public void UpdateStatus(PurchaseReturnDTO purchaseReturnDto, Status status)
        {
            PurchaseReturnRepository.UpdateStatus(purchaseReturnDto.PRNo, (int)status);
        }

        #endregion
    }
}